package com.haochu.xxl.ui;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Rect;
import android.media.SoundPool;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationSet;

import com.haochu.xxl.R;
import com.haochu.xxl.animate.ChangeAnimation;
import com.haochu.xxl.animate.FallAnimation;
import com.haochu.xxl.animate.LRAnimator;
import com.haochu.xxl.animate.RemoveAnimation;
import com.haochu.xxl.animate.UDAnimator;
import com.haochu.xxl.map.MapUtil;
import com.haochu.xxl.model.PointItem;
import com.haochu.xxl.util.BitmapUtil;
import com.haochu.xxl.util.Constants;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author fuhuichao
 * @description 游戏主界面view
 * @date 2017-9-10 13:55:31
 */
@SuppressLint("ClickableViewAccessibility")
public class GameSceneView extends View {

    private static final String TAG = "GameMapView";
    private GameSceneActivity context;
    // 屏幕尺寸
    private int screenWidth, screenHeight;
    // 元素点图片
    private Bitmap[] items, items_c, item_gold;
    // 左右摇头/上下点头动画图片，key为point的type，bitmap[]为动画帧数组，下标为point的animIndex..
    private Map<Integer, List<Bitmap>> items_anim_lr, items_anim_ud;
    // 爆炸图片
    private Bitmap[] items_boom;
    // 元素背景
    private Bitmap bgPoint;
    // 舞台背景
    private Bitmap bgScene;
    // 气泡背景
    private Bitmap bgBubble;
    // 工具栏图标
    private Bitmap toolRandom, toolHammer, toolTimer, toolChange, toolMagic;
    // key：当前可掉落的元素，value：可掉落的格子数
//    Map<PointItem, Integer> fallMap = new HashMap<>();
    // 当前游戏地图数组
    private int[][] dataMap;
    // 游戏界面画笔
    private Paint paint;
    // 元素集合
    private List<PointItem> points;
    private List<PointItem> points_init = new ArrayList<>();
    private List<PointItem> points_remove = new ArrayList<>();
    // 被选中的元素
    private PointItem pointChecked;
    // 交换的两个元素点
    private PointItem p11, p22;
    // 元素移动动画集合
    private AnimationSet animationSet;
    // 动画是否结束
    private boolean isAnimationEnd = true;
    // 游戏音效
    private SoundPool soundPool;
    // 连续消除时的音效
    private Integer[] soundPoolArrayRemove = null;
    // 连续消除后的音效
    private Integer[] soundPoolArrayContinue = null;
    // 当前播放音效
    private int soundPoolIndex;

    public GameSceneView(Context context) {
        super(context);
        init(context);
    }

    public GameSceneView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public GameSceneView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        refresh(canvas);
    }

    public boolean doTouchEvent(MotionEvent event) {
        invalidate();
        return true;
    }

    /**
     * TODO 刷新游戏主界面
     */
    protected void refresh(Canvas canvas) {
        try {

            // 画舞台背景
            canvas.drawBitmap(bgScene, 0, 0, null);

            // 画气泡
            drawBubble(canvas);

            // 画元素点背景【黑框框】
            for (PointItem point : points_init) {
                drawItem(canvas, bgPoint, point.getX(), point.getY());
            }

            // 画元素点【动物】
            for (PointItem point : points) {
                int px = point.getX();
                int py = point.getY();
                int pi = point.getIndex();
                int pt = point.getType();
                int iud = point.getAnimIndexUD();
                int ilr = point.getAnimIndexLR();
                boolean animating = point.isAnimating();

                Bitmap bm = null;

                switch (pt) {
                    case 0:// 画普通元素
                        if (point.equals(pointChecked)) {
                            bm = items_c[pi];
                        } else {
                            bm = items[pi];
                        }
                        break;
                    case 1:// 画爆炸效果
                        bm = items_boom[pi];
                        break;
                    case 2:// 画金边特效
                        bm = item_gold[pi];
                        break;
                    case 3:// 画上下点头特效
                        List<Bitmap> list_ud = items_anim_ud.get(pi);
                        bm = list_ud.get(iud);
                        if (!animating) {
                            point.setAnimating(true);
                            new UDAnimator(this, point, list_ud.size()).start();
                        }
                        break;
                    case 4:// 画左右摇头特效
                        List<Bitmap> list_lr = items_anim_lr.get(pi);
                        bm = list_lr.get(ilr);
                        if (!animating) {
                            point.setAnimating(true);
                            new LRAnimator(this, point, list_lr.size()).start();
                        }
                        break;
                }

                // 画元素
                drawItem(canvas, bm, px, py);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 初始化
     */
    public void init(Context context) {
        this.context = (GameSceneActivity) context;

        // 初始化画笔
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor(Color.DKGRAY);
        paint.setTextSize(22);
        paint.setTextAlign(Align.LEFT);

        // 初始化游戏元素
        items = new Bitmap[6];
        items[0] = BitmapFactory.decodeResource(this.getResources(), R.drawable.blue);
        items[1] = BitmapFactory.decodeResource(this.getResources(), R.drawable.brown);
        items[2] = BitmapFactory.decodeResource(this.getResources(), R.drawable.green);
        items[3] = BitmapFactory.decodeResource(this.getResources(), R.drawable.purple);
        items[4] = BitmapFactory.decodeResource(this.getResources(), R.drawable.red);
        items[5] = BitmapFactory.decodeResource(this.getResources(), R.drawable.yellow);

        // 初始化游戏元素[选中状态]
        items_c = new Bitmap[6];
        items_c[0] = BitmapFactory.decodeResource(this.getResources(), R.drawable.blue_c);
        items_c[1] = BitmapFactory.decodeResource(this.getResources(), R.drawable.brown_c);
        items_c[2] = BitmapFactory.decodeResource(this.getResources(), R.drawable.green_c);
        items_c[3] = BitmapFactory.decodeResource(this.getResources(), R.drawable.purple_c);
        items_c[4] = BitmapFactory.decodeResource(this.getResources(), R.drawable.red_c);
        items_c[5] = BitmapFactory.decodeResource(this.getResources(), R.drawable.yellow_c);

        // 初始化游戏元素[金边状态]
        item_gold = new Bitmap[6];
        item_gold[0] = BitmapFactory.decodeResource(this.getResources(), R.drawable.blue_gold);
        item_gold[1] = BitmapFactory.decodeResource(this.getResources(), R.drawable.brown_gold);
        item_gold[2] = BitmapFactory.decodeResource(this.getResources(), R.drawable.green_gold);
        item_gold[3] = BitmapFactory.decodeResource(this.getResources(), R.drawable.purple_gold);
        item_gold[4] = BitmapFactory.decodeResource(this.getResources(), R.drawable.red_gold);
        item_gold[5] = BitmapFactory.decodeResource(this.getResources(), R.drawable.yellow_gold);

        // 爆炸动画逐帧图片
        items_boom = new Bitmap[4];
        items_boom[0] = BitmapFactory.decodeResource(this.getResources(), R.drawable.boom_0);
        items_boom[1] = BitmapFactory.decodeResource(this.getResources(), R.drawable.boom_1);
        items_boom[2] = BitmapFactory.decodeResource(this.getResources(), R.drawable.boom_2);
        items_boom[3] = BitmapFactory.decodeResource(this.getResources(), R.drawable.boom_3);

        // 左右摇头动画图片帧
        items_anim_lr = new HashMap<>();
        List<Bitmap> list = new ArrayList<>();
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/blue/blue_lr_0.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/blue/blue_lr_1.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/blue/blue_lr_2.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/blue/blue_lr_3.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/blue/blue_lr_4.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/blue/blue_lr_5.png"));
        items_anim_lr.put(Constants.POINT_COLOR_BLUE, list);

        list = new ArrayList<>();
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/brown/brown_lr_0.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/brown/brown_lr_1.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/brown/brown_lr_2.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/brown/brown_lr_3.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/brown/brown_lr_4.png"));
        items_anim_lr.put(Constants.POINT_COLOR_BROWN, list);

        list = new ArrayList<>();
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/green/green_lr_0.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/green/green_lr_1.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/green/green_lr_2.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/green/green_lr_3.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/green/green_lr_4.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/green/green_lr_5.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/green/green_lr_6.png"));
        items_anim_lr.put(Constants.POINT_COLOR_GREEN, list);

        list = new ArrayList<>();
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/purple/purple_lr_0.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/purple/purple_lr_1.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/purple/purple_lr_2.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/purple/purple_lr_3.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/purple/purple_lr_4.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/purple/purple_lr_5.png"));
        items_anim_lr.put(Constants.POINT_COLOR_PURPLE, list);

        list = new ArrayList<>();
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/red/red_lr_0.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/red/red_lr_1.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/red/red_lr_2.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/red/red_lr_3.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/red/red_lr_4.png"));
        items_anim_lr.put(Constants.POINT_COLOR_RED, list);

        list = new ArrayList<>();
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/yellow/yellow_lr_0.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/yellow/yellow_lr_1.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/yellow/yellow_lr_2.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/yellow/yellow_lr_3.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/yellow/yellow_lr_4.png"));
        items_anim_lr.put(Constants.POINT_COLOR_YELLOW, list);

        // 上下点头特效
        items_anim_ud = new HashMap<>();
        list = new ArrayList<>();
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/blue/blue_ud_0.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/blue/blue_ud_1.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/blue/blue_ud_2.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/blue/blue_ud_3.png"));
        items_anim_ud.put(Constants.POINT_COLOR_BLUE, list);

        list = new ArrayList<>();
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/brown/brown_ud_0.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/brown/brown_ud_1.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/brown/brown_ud_2.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/brown/brown_ud_3.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/brown/brown_ud_4.png"));
        items_anim_ud.put(Constants.POINT_COLOR_BROWN, list);

        list = new ArrayList<>();
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/green/green_ud_0.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/green/green_ud_1.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/green/green_ud_2.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/green/green_ud_3.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/green/green_ud_4.png"));
        items_anim_ud.put(Constants.POINT_COLOR_GREEN, list);

        list = new ArrayList<>();
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/purple/purple_ud_0.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/purple/purple_ud_1.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/purple/purple_ud_2.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/purple/purple_ud_3.png"));
        items_anim_ud.put(Constants.POINT_COLOR_PURPLE, list);

        list = new ArrayList<>();
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/red/red_ud_0.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/red/red_ud_1.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/red/red_ud_2.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/red/red_ud_3.png"));
        items_anim_ud.put(Constants.POINT_COLOR_RED, list);

        list = new ArrayList<>();
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/yellow/yellow_ud_0.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/yellow/yellow_ud_1.png"));
        list.add(BitmapUtil.getFromAssets(this.getResources(), "anim/yellow/yellow_ud_2.png"));
        items_anim_ud.put(Constants.POINT_COLOR_YELLOW, list);

        // 元素点背景
        bgPoint = BitmapFactory.decodeResource(this.getResources(), R.drawable.bg_point);

        // 舞台背景
        bgScene = BitmapFactory.decodeResource(this.getResources(), R.drawable.bg_scene);

        // 气泡背景
        bgBubble = BitmapFactory.decodeResource(this.getResources(), R.drawable.bg_bubble);
        bgBubble = Bitmap.createScaledBitmap(bgBubble, Constants.WIDTH_BUBBLE, Constants.WIDTH_BUBBLE, true);

        // 工具栏图标
        toolRandom = BitmapFactory.decodeResource(this.getResources(), R.drawable.tool_random);
        toolRandom = Bitmap.createScaledBitmap(toolRandom, Constants.WIDTH_BUBBLE - Constants.WIDTH_TOOL2BUBBLE_DIFF, Constants.WIDTH_BUBBLE - Constants.WIDTH_TOOL2BUBBLE_DIFF, true);
        toolHammer = BitmapFactory.decodeResource(this.getResources(), R.drawable.tool_hammer);
        toolHammer = Bitmap.createScaledBitmap(toolHammer, Constants.WIDTH_BUBBLE - Constants.WIDTH_TOOL2BUBBLE_DIFF, Constants.WIDTH_BUBBLE - Constants.WIDTH_TOOL2BUBBLE_DIFF, true);
        toolTimer = BitmapFactory.decodeResource(this.getResources(), R.drawable.tool_timer);
        toolTimer = Bitmap.createScaledBitmap(toolTimer, Constants.WIDTH_BUBBLE - Constants.WIDTH_TOOL2BUBBLE_DIFF, Constants.WIDTH_BUBBLE - Constants.WIDTH_TOOL2BUBBLE_DIFF, true);
        toolChange = BitmapFactory.decodeResource(this.getResources(), R.drawable.tool_change);
        toolChange = Bitmap.createScaledBitmap(toolChange, Constants.WIDTH_BUBBLE - Constants.WIDTH_TOOL2BUBBLE_DIFF, Constants.WIDTH_BUBBLE - Constants.WIDTH_TOOL2BUBBLE_DIFF, true);
        toolMagic = BitmapFactory.decodeResource(this.getResources(), R.drawable.tool_magic);
        toolMagic = Bitmap.createScaledBitmap(toolMagic, Constants.WIDTH_BUBBLE - Constants.WIDTH_TOOL2BUBBLE_DIFF, Constants.WIDTH_BUBBLE - Constants.WIDTH_TOOL2BUBBLE_DIFF, true);

        // 初始化地图
        points = new ArrayList<PointItem>();
        dataMap = MapUtil.map_1;
        for (int i = 0; i < dataMap.length; i++) {
            for (int j = 0; j < dataMap[i].length; j++) {
//                if (dataMap[i][j] == 1) {
//                    int x = j * Constants.SIZE + Constants.MARGIN_LEFT;
//                    int y = i * Constants.SIZE + Constants.MARGIN_TOP;
//                    // 保存元素点
//                    points.add(createRandomPoint(x, y));
//                    points_init.add(createRandomPoint(x, y));
//                }

                // TODO 模拟测试数据
                int x = j * Constants.SIZE + Constants.MARGIN_LEFT;
                int y = i * Constants.SIZE + Constants.MARGIN_TOP;
                points.add(new PointItem(x, y, dataMap[i][j]));
                points_init.add(new PointItem(x, y, dataMap[i][j]));
            }
        }
    }

    /**
     * 随机生成一个元素
     */
    public PointItem createRandomPoint(int x, int y) {
        int random = (int) (items.length * Math.random());
        return new PointItem(x, y, random);
    }

    /**
     * 画元素
     */
    public void drawItem(Canvas canvas, Bitmap bm, int x, int y) {
        Rect src = null, dst = null;

        // 若元素在页面边界外，则不画
        if (y < Constants.MARGIN_TOP && y + Constants.SIZE < Constants.MARGIN_TOP) {
            return;
        }
        // 若元素有一部分在边界外，则只画边界内的区域
        if (y < Constants.MARGIN_TOP && y + Constants.SIZE >= Constants.MARGIN_TOP) {
            bm = Bitmap.createScaledBitmap(bm, Constants.SIZE, Constants.SIZE, true);
            src = new Rect(0, Constants.MARGIN_TOP - y, Constants.SIZE, Constants.SIZE);
            dst = new Rect(x, Constants.MARGIN_TOP, x + Constants.SIZE, y + Constants.SIZE);
        }
        // 若元素全部在边界内，则全部显示
        if (y >= Constants.MARGIN_TOP && y + Constants.SIZE >= Constants.MARGIN_TOP) {
            src = null;
            dst = new Rect(x, y, x + Constants.SIZE, y + Constants.SIZE);
        }
        canvas.drawBitmap(bm, src, dst, paint);
    }

    /**
     * 画气泡和工具
     */
    public void drawBubble(Canvas canvas) {
        int x = Constants.MARGIN_TOOL_LEFT;
        int y = screenHeight - Constants.MARGIN_TOOL_BOTTOM - Constants.WIDTH_BUBBLE;
        canvas.drawBitmap(toolRandom, x + Constants.WIDTH_TOOL2BUBBLE_DIFF / 2, y - 30 + Constants.WIDTH_TOOL2BUBBLE_DIFF / 2, paint);
        canvas.drawBitmap(bgBubble, x, y - 30, paint);

        x += Constants.WIDTH_BUBBLE + Constants.PADDING_TOOL;
        canvas.drawBitmap(toolHammer, x + Constants.WIDTH_TOOL2BUBBLE_DIFF / 2, y - 5 + Constants.WIDTH_TOOL2BUBBLE_DIFF / 2, paint);
        canvas.drawBitmap(bgBubble, x, y - 5, paint);

        x += Constants.WIDTH_BUBBLE + Constants.PADDING_TOOL;
        canvas.drawBitmap(toolTimer, x + Constants.WIDTH_TOOL2BUBBLE_DIFF / 2, y - 25 + Constants.WIDTH_TOOL2BUBBLE_DIFF / 2, paint);
        canvas.drawBitmap(bgBubble, x, y - 25, paint);

        x += Constants.WIDTH_BUBBLE + Constants.PADDING_TOOL;
        canvas.drawBitmap(toolChange, x + Constants.WIDTH_TOOL2BUBBLE_DIFF / 2, y - 8 + Constants.WIDTH_TOOL2BUBBLE_DIFF / 2, paint);
        canvas.drawBitmap(bgBubble, x, y - 8, paint);

        x += Constants.WIDTH_BUBBLE + Constants.PADDING_TOOL;
        canvas.drawBitmap(toolMagic, x + Constants.WIDTH_TOOL2BUBBLE_DIFF / 2, y - 28 + Constants.WIDTH_TOOL2BUBBLE_DIFF / 2, paint);
        canvas.drawBitmap(bgBubble, x, y - 28, paint);
    }

    /**
     * 交换两个元素
     *
     * @param undo 是否可能会还原本次交换，若本次交换已经是撤销了，则不再继续撤销
     */
    public void change(PointItem p1, PointItem p2, final boolean undo) {
        p11 = p1;
        p22 = p2;
        ChangeAnimation changeAnimation = new ChangeAnimation(this, p11, p22);
        changeAnimation.setAnimationListener(new AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                isAnimationEnd = false;
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                isAnimationEnd = true;
                // 每次交换后将连续消除的音效重置为0
                soundPoolIndex = 0;
                // 动画结束后继续检测，如果没有消除则重新交换
                if (!checkAndRemove() && undo) {
                    change(p11, p22, false);
                }
            }
        });
        this.startAnimation(changeAnimation);
    }

    /**
     * 检查界面是否有可消除的元素
     */
    public boolean checkAndRemove() {
        try {

            // 横向检测
            sortX();

            // 容器存放比较中的元素，相同的移入，遇到不相同且不足3个则清空，大于等于3个则加入remove后清空
            List<PointItem> container = new ArrayList<>();
            for (int i = 0; i < points.size(); i++) {
                PointItem point = points.get(i);

                // 容器为空，则移入
                if (container.isEmpty()) {
                    container.add(point);
                } else {
                    PointItem last = container.get(container.size() - 1);
                    if (point.nextEqX(last)) {
                        container.add(point);
                        // 判断最后一个
                        if (i == points.size() - 1 && container.size() >= 3) {
                            points_remove.addAll(container);

                            // 检查是否有T字型的可消除的
                            boolean hasT = checkT();
                            if (!hasT) {
                                // 如果没有T字型，则检查长度，如果为4个，则生成竖向特效，如果大于4个，则生成[消除所有]的特效
                                if (container.size() == 4) {
                                    checkUD(container);
                                } else if (points_remove.size() > 4) {

                                }
                            }

                            container.clear();
                        }
                    } else {
                        if (container.size() >= 3) {
                            points_remove.addAll(container);

                            // 检查是否有T字型的可消除的
                            boolean hasT = checkT();
                            if (!hasT) {
                                // 如果没有T字型，则检查长度，如果为4个，则生成竖向特效，如果大于4个，则生成[消除所有]的特效
                                if (container.size() == 4) {
                                    checkUD(container);
                                } else if (points_remove.size() > 4) {

                                }
                            }

                        }
                        container.clear();
                        container.add(point);
                    }
                }
            }

            if (points_remove.size() > 0) {
                removeAndFall();
                return true;
            }

            // 纵向检测
            sortY();

            // 容器存放比较中的元素，相同的移入，遇到不相同且不足3个则清空，大于等于3个则加入remove后清空
            container = new ArrayList<>();
            for (int i = 0; i < points.size(); i++) {
                PointItem point = points.get(i);

                // 容器为空，则移入
                if (container.isEmpty()) {
                    container.add(point);
                } else {
                    PointItem last = container.get(container.size() - 1);
                    if (point.nextEqY(last)) {
                        container.add(point);
                        // 判断最后一个
                        if (i == points.size() - 1 && container.size() >= 3) {
                            points_remove.addAll(container);

                            // 检查长度，如果为4个，则生成竖向特效，如果大于4个，则生成[消除所有]的特效
                            if (container.size() == 4) {
                                checkLR(container);
                            } else if (points_remove.size() > 4) {

                            }

                            container.clear();
                        }
                    } else {
                        if (container.size() >= 3) {
                            points_remove.addAll(container);

                            // 检查长度，如果为4个，则生成竖向特效，如果大于4个，则生成[消除所有]的特效
                            if (container.size() == 4) {
                                checkLR(container);
                            } else if (points_remove.size() > 4) {

                            }
                        }
                        container.clear();
                        container.add(point);
                    }
                }
            }

            if (points_remove.size() > 0) {
                removeAndFall();
                return true;
            }

        } catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG, "Error: " + e.getCause());
        }
        return false;
    }

    /**
     * 将points_remove中全部标记为逻辑删除
     */
    public void setAllRemovable() {
        for (PointItem p : points_remove) {
            p.setRemove(true);
        }
    }

    /**
     * 检查4个相连的特效
     */
    public void checkLR(List<PointItem> container) {
        for (PointItem p : container) {
            if (p.positionEq(p11) || p.positionEq(p22)) {
                p.setType(Constants.POINT_TYPE_LR);
                p.setRemove(false);
                points_remove.remove(p);
                break;
            }
        }
    }
    public void checkUD(List<PointItem> container) {
        for (PointItem p : container) {
            if (p.positionEq(p11) || p.positionEq(p22)) {
                p.setType(Constants.POINT_TYPE_UD);
                p.setRemove(false);
                points_remove.remove(p);
                break;
            }
        }
    }

    /**
     * 检查[T]字型的消除
     */
    public boolean checkT() {
        setAllRemovable();

        // 遍历横向，依次查找纵向是否有相邻的可消除的[即可以组成‘T’字型的]
        List<PointItem> points_T = new ArrayList<>();
        for (PointItem p : points_remove) {
            int x = p.getX();

            // 向上检测T字型
            int y = p.getY() - Constants.SIZE;
            // 临时变量，记录[上一个]
            PointItem temp = p;
            while (true) {
                PointItem pup = getPoint(x, y);
                y -= Constants.SIZE;
                if (pup != null && pup.isNotRemove() && pup.nextEqY(temp)) {
                    points_T.add(pup);
                } else {
                    break;
                }
                // 将当前pup标记为[上一个]
                temp = pup;
            }

            // 向下检测T字型
            y = p.getY() + Constants.SIZE;
            // 临时变量，记录[上一个]
            temp = p;
            while (true) {
                PointItem pdp = getPoint(x, y);
                y += Constants.SIZE;
                if (pdp != null && pdp.isNotRemove() && pdp.nextEqY(temp)) {
                    points_T.add(pdp);
                } else {
                    break;
                }
                // 将当前pdp标记为[上一个]
                temp = pdp;
            }
            if (points_T.size() >= 2) {
                // 保留[T]字型连接处的元素，并设置为金边特效
                p.setRemove(false);
                p.setType(2);
                points_remove.remove(p);
                break;
            } else {
                points_T.clear();
            }
        }

        if (points_T.isEmpty()) {
            return false;
        } else {
            points_remove.addAll(points_T);

            // 再次将合并后的points_remove中全部标记为逻辑删除
            setAllRemovable();

            return true;
        }
    }

    /**
     * 如果有金边元素，则消除金边附近12个元素
     * 规则为：
     * . . o
     * . o o o
     * o o ● o o
     * . o o o
     * . . o
     */
    public void checkForGold() {
        List<PointItem> points_remove_gold = new ArrayList<>();
        for (PointItem p : points_remove) {
            if (p.getType() == 2) {
                int x = p.getX();
                int y = p.getY();
                PointItem pi = null;

                // 第一列
                pi = getPoint(x - Constants.SIZE * 2, y);
                if (pi != null && pi.isNotRemove()) {
                    points_remove_gold.add(pi);
                }

                // 第二列
                pi = getPoint(x - Constants.SIZE, y - Constants.SIZE);
                if (pi != null && pi.isNotRemove()) {
                    points_remove_gold.add(pi);
                }
                pi = getPoint(x - Constants.SIZE, y);
                if (pi != null && pi.isNotRemove()) {
                    points_remove_gold.add(pi);
                }
                pi = getPoint(x - Constants.SIZE, y + Constants.SIZE);
                if (pi != null && pi.isNotRemove()) {
                    points_remove_gold.add(pi);
                }

                // 第三列
                pi = getPoint(x, y - Constants.SIZE * 2);
                if (pi != null && pi.isNotRemove()) {
                    points_remove_gold.add(pi);
                }
                pi = getPoint(x, y - Constants.SIZE);
                if (pi != null && pi.isNotRemove()) {
                    points_remove_gold.add(pi);
                }
                pi = getPoint(x, y + Constants.SIZE);
                if (pi != null && pi.isNotRemove()) {
                    points_remove_gold.add(pi);
                }
                pi = getPoint(x, y + Constants.SIZE * 2);
                if (pi != null && pi.isNotRemove()) {
                    points_remove_gold.add(pi);
                }

                // 第四列
                pi = getPoint(x + Constants.SIZE, y - Constants.SIZE);
                if (pi != null && pi.isNotRemove()) {
                    points_remove_gold.add(pi);
                }
                pi = getPoint(x + Constants.SIZE, y);
                if (pi != null && pi.isNotRemove()) {
                    points_remove_gold.add(pi);
                }
                pi = getPoint(x + Constants.SIZE, y + Constants.SIZE);
                if (pi != null && pi.isNotRemove()) {
                    points_remove_gold.add(pi);
                }

                // 第五列
                pi = getPoint(x + Constants.SIZE * 2, y);
                if (pi != null && pi.isNotRemove()) {
                    points_remove_gold.add(pi);
                }
            }
        }

        points_remove.addAll(points_remove_gold);
        setAllRemovable();
    }

    /**
     * 检测左右摇头特效，消除本行
     */
    public void checkForLR() {
        List<PointItem> points_remove_lr = new ArrayList<>();
        for (PointItem p : points_remove) {
            if (p.getType() == Constants.POINT_TYPE_LR) {
                // 找到最左边的点
                int x = Constants.MARGIN_LEFT;
                int y = p.getY();
                while (true) {
                    PointItem pi = getPoint(x, y);
                    x += Constants.SIZE;
                    if (pi != null) {
                        if (pi.isNotRemove()) {
                            pi.setRemove(true);
                            points_remove_lr.add(pi);
                        }
                    } else {
                        break;
                    }
                }
            }
        }
        points_remove.addAll(points_remove_lr);
    }

    /**
     * 检测上下摇头特效，消除本列
     */
    public void checkForUD() {
        List<PointItem> points_remove_ud = new ArrayList<>();
        for (PointItem p : points_remove) {
            if (p.getType() == Constants.POINT_TYPE_UD) {
                // 找到最上面边的点
                int x = p.getX();
                int y = Constants.MARGIN_TOP;
                while (true) {
                    PointItem pi = getPoint(x, y);
                    y += Constants.SIZE;
                    if (pi != null) {
                        if (pi.isNotRemove()) {
                            pi.setRemove(true);
                            points_remove_ud.add(pi);
                        }
                    } else {
                        break;
                    }
                }
            }
        }
        points_remove.addAll(points_remove_ud);
    }

    /**
     * 需要消除的元素点
     */
    public void removePoint(PointItem point) {
        points.remove(point);
    }

    /**
     * 开始元素移除的动画
     */
    public void setRemoveAnimationListener() {
        AnimationSet animationSetRemove = new AnimationSet(true);

        // 移除元素
        for (PointItem p : points_remove) {
            animationSetRemove.addAnimation(new RemoveAnimation(this, p));
        }
        animationSetRemove.setAnimationListener(new AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                isAnimationEnd = false;

                // 播放消失的声音
                playSoundSingle(soundPoolArrayRemove[soundPoolIndex]);
                if (soundPoolIndex < soundPoolArrayRemove.length - 1) {
                    soundPoolIndex++;
                }
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                isAnimationEnd = true;

                // 移除元素点
                for (PointItem p : points_remove) {
                    removePoint(p);
                }
                points_remove.clear();

                // 注册掉落动画监听
                setFallAnimationListener(animationSet);
            }
        });
        this.startAnimation(animationSetRemove);
    }

    /**
     * 设置掉落动画监听并开始掉落
     */
    public void setFallAnimationListener(AnimationSet animationSet) {

        animationSet.setAnimationListener(new AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                isAnimationEnd = false;
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                isAnimationEnd = true;
                // 动画结束后继续检测
                boolean isContinue = checkAndRemove();
                // TODO 若动画完成后，判断当前消除的次数，播放对应的音效
                if (!isContinue) {
                    if (soundPoolIndex > 1) {
                        int index = soundPoolIndex - 1;
                        index = index > soundPoolArrayContinue.length - 1 ? soundPoolArrayContinue.length - 1 : index;
                        playSoundSingle(soundPoolArrayContinue[index]);
                    }
                    soundPoolIndex = 0;
                }
            }
        });
        this.startAnimation(animationSet);
    }

    /**
     * 播放一次音效
     */
    public void playSoundSingle(Integer index) {
        soundPool.play(index, 1, 1, 1, 0, 1);
    }

    /**
     * 循环播放音效
     */
    public void playSoundCycle(SoundPool soundPool, Integer index) {
        soundPool.play(index, 1, 1, 1, 0, 1);
    }

    /**
     * 0.顶部生成新元素
     * 1.移除元素
     * 2.播放移除音效
     * 3.掉落元素
     * 4.播放连续掉落音效
     */
    public void removeAndFall() {
        setAllRemovable();

        // 检查本次消除是否有金边，有则消除金边附近的12个元素
        checkForGold();

        // 检查本次消除是否有左右摇头特效，有则消除本行所有元素
        checkForLR();

        // 检查本次消除是否有上下摇头特效，有则消除本列所有元素
        checkForUD();

        // 在将要消除的元素的最顶部生成新的元素
        for (PointItem p : points_remove) {
            points.add(createPointTop(p));
        }

        // 移除元素前先获取掉落元素的集合
        Map<PointItem, Integer> fallMap = getFallMap();
        if (!fallMap.isEmpty()) {

            // 创建动画，参数表示他的子动画是否共用一个插值器
            animationSet = new AnimationSet(true);

            // 遍历可掉落的元素点，将上方的元素依次掉落
            for (Map.Entry<PointItem, Integer> entry : fallMap.entrySet()) {
                PointItem point = entry.getKey();
                Integer len = entry.getValue();
                animationSet.addAnimation(new FallAnimation(this, point, len));
            }
        }

        // 移除元素
        setRemoveAnimationListener();
    }

    /**
     * 获取可掉落的元素点
     */
    public Map<PointItem, Integer> getFallMap() {
        Map<PointItem, Integer> fallMap = new HashMap<>();
        // 遍历所有标记要消除的元素，将上方的元素标记[掉落格子数依次+1]
        for (PointItem point : points_remove) {
            // 获取当前元素点上方所有未标记删除的元素
            int x = point.getX();
            int y = point.getY() - Constants.SIZE;
            while (true) {
                PointItem pup = getPoint(x, y);
                y -= Constants.SIZE;
                if (pup != null) {
                    // 如果上方元素存在，且未标记为删除，则标记该元素为下落元素
                    if (pup.isNotRemove()) {
                        // 如果下落元素已存在，则将其下落格子数+1，如果不存在，则添加进下落元素的集合
                        int len = 1;
                        if (fallMap.containsKey(pup)) {
                            len = fallMap.get(pup) + 1;
                        }
                        fallMap.put(pup, len);
                    }
                } else {
                    break;
                }
            }
        }
        return fallMap;
    }

    /**
     * 在{point}元素所在列的最顶部生成新的元素
     */
    public PointItem createPointTop(PointItem p) {
        int x = p.getX();
        int y = Constants.MARGIN_TOP - Constants.SIZE;
        while (getPoint(x, y) != null) {
            y -= Constants.SIZE;
        }
        return createRandomPoint(x, y);
    }

    /**
     * @deprecated 判断坐标在游戏舞台内
     */
    public boolean checkInScene(int x, int y) {
        return x >= Constants.MARGIN_LEFT
                && x < screenWidth - Constants.MARGIN_RIGHT
                && y >= Constants.MARGIN_TOP
                && y < Constants.MARGIN_TOP + dataMap.length * Constants.SIZE;
    }

    /**
     * 将list排序，按Y升序，Y相等则按X升序
     */
    public void sortX() {
        Collections.sort(points, new Comparator<PointItem>() {
            public int compare(PointItem o1, PointItem o2) {
                if (o1.getY() == o2.getY()) {
                    return o1.getX() - o2.getX();
                }
                return o1.getY() - o2.getY();
            }
        });
    }

    /**
     * 将list排序，按X升序，X相等则按Y升序
     */
    public void sortY() {
        Collections.sort(points, new Comparator<PointItem>() {
            public int compare(PointItem o1, PointItem o2) {
                if (o1.getX() == o2.getX()) {
                    return o1.getY() - o2.getY();
                }
                return o1.getX() - o2.getX();
            }
        });
    }

    /**
     * 根据坐标返回元素对象
     */
    public PointItem getPoint(int x, int y) {
        PointItem result = null;
        for (PointItem point : points) {
            if (x == point.getX() && y == point.getY()) {
                result = point;
                break;
            }
        }
        return result;
    }

    /**
     * 获取点击的坐标对应的元素点
     */
    public PointItem getPointByTouch(float x, float y) {
        PointItem p = null;
        for (PointItem point : points) {
            int px = point.getX();
            int py = point.getY();
            // 判断点击的坐标是否为元素点
            if (x > px && x < px + Constants.SIZE && y > py && y < py + Constants.SIZE) {
                p = point;
            }
        }
        return p;
    }

    public List<PointItem> getPoints() {
        return points;
    }

    public Bitmap[] getItems() {
        return items;
    }

    public Bitmap[] getItems_c() {
        return items_c;
    }

    public boolean isAnimationEnd() {
        return isAnimationEnd;
    }

    public PointItem getPointChecked() {
        return pointChecked;
    }

    public void setPointChecked(PointItem pointChecked) {
        this.pointChecked = pointChecked;
    }

    public void setSoundPool(SoundPool soundPool) {
        this.soundPool = soundPool;
    }

    public void setSoundPoolArrayRemove(Integer[] soundPoolArrayRemove) {
        this.soundPoolArrayRemove = soundPoolArrayRemove;
    }

    public void setScreenWidth(int screenWidth) {
        this.screenWidth = screenWidth;
    }

    public void setScreenHeight(int screenHeight) {
        this.screenHeight = screenHeight;
    }

    public void setSoundPoolArrayContinue(Integer[] soundPoolArrayContinue) {
        this.soundPoolArrayContinue = soundPoolArrayContinue;
    }
}
